#include <QApplication>
#include <QDataStream>
#include <QString>
#include <QDebug>
#include <QBuffer>
#include <typeinfo>
#include "capturethread.h"
#include <iostream>
#include <QFile>
#include <QDesktopWidget>

#define _DEVICE_NAME "/dev/video0"
#define CLEAR(x) memset(&(x), 0, sizeof(x))
#define _CAPTURE_YUV_WIDTH 720
#define _CAPTURE_YUV_HEIGHT 576

CaptureThread::CaptureThread(QMainWindow *parent) :
    QThread(parent)
{
    this->parent=/*(MainWindow*)*/parent;
    devam=true;
    fd = -1;
//    fout = fopen("yuv.yuv", "wb+");
    pSdlModule = NULL;
    pSurface = NULL;
    pSdlModule = SdlModuleInit(parent->winId(),/*QApplication::desktop()->width(), QApplication::desktop()->height(),*/
                               _CAPTURE_YUV_WIDTH, _CAPTURE_YUV_HEIGHT,
                               _CAPTURE_YUV_WIDTH, _CAPTURE_YUV_HEIGHT, 44100, SDL_AUDIO_S16, 2, 120);
    if(NULL == pSdlModule)
    {
        qDebug() << "sdl init failed!";
        return ;
    }
    pSurface = AvSDLYUVCreate(pSdlModule, 0, 0, _CAPTURE_YUV_WIDTH, _CAPTURE_YUV_HEIGHT);

}

void CaptureThread::run()
{
    fd = -1;
    fd = v4l2_open(_DEVICE_NAME, O_RDWR | O_NONBLOCK, 0);
    if (fd < 0) {
           qDebug("Cannot open device");
           return;
    }
    struct v4l2_capability capability;
    CLEAR(capability);
    if(-1 == ioctl(fd, VIDIOC_QUERYCAP, &capability))
    {
        perror("VIDIOC_QUERYCAP");
        return;
    }
    if(0 == (capability.capabilities & V4L2_CAP_VIDEO_CAPTURE))
    {
        qDebug() << "This capture card not suspend video cature.";
        return;
    }
    //set standard std directed
    v4l2_std_id u32VideoStdId = V4L2_STD_PAL;
    if(-1 == ioctl(fd, VIDIOC_S_STD, &u32VideoStdId))
    {
        perror("VIDIOC_S_STD");
        return;
    }

    struct v4l2_input input;
    CLEAR(input);
    input.index = 1;
    if(-1 == ioctl(fd, VIDIOC_ENUMINPUT, &input))
    {
        perror("VIDIOC_G_INPUT");
        return;
    }
//    input.std = V4L2_STD_PAL;
    if(-1 == ioctl(fd, VIDIOC_S_INPUT, &input))
    {
        perror("VIDIOC_S_INPUT");
        return;
    }

    struct v4l2_format              fmt;
    static unsigned char *dst_buf;
    CLEAR(fmt);
    ioctl(fd, VIDIOC_G_FMT, &fmt);

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width       = _CAPTURE_YUV_WIDTH;
    fmt.fmt.pix.height      = _CAPTURE_YUV_HEIGHT;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
    if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt))
    {
        perror("VIDIOC_S_FMT");
        return;
    }
    dst_buf = (unsigned char*)malloc(fmt.fmt.pix.sizeimage);

    struct v4l2_requestbuffers      req;
    struct v4l2_buffer              buf;
    CLEAR(req);
    req.count = 20;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if (-1 == ioctl(fd, VIDIOC_REQBUFS, &req))
    {
        perror("VIDIOC_REQBUFS");
        return;
    }

    if(req.count < 5)
    {
        perror("VIDIOC_REQBUFS");
        return;
    }

    videio_buffers = (VidioBuffer *)calloc(req.count, sizeof(*videio_buffers));
    for (i = 0; i < req.count; ++i)
    {
           CLEAR(buf);

           buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
           buf.memory      = V4L2_MEMORY_MMAP;
           buf.index       = i;

           if(-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
           {
               perror("VIDIOC_QUERYBUF");
               return;
           }

           videio_buffers[i].length = buf.length;
           videio_buffers[i].start = mmap(NULL, buf.length,
                         PROT_READ | PROT_WRITE, MAP_SHARED,
                         fd, buf.m.offset);

           if (MAP_FAILED == videio_buffers[i].start) {
                   perror("mmap");
                   return;
           }
           //into the buffer queue
           if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
           {
               perror("VIDIOC_QBUF");
               return;
           }
    }
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd, VIDIOC_STREAMON, &type);
    int di=0;
    while(devam){
        do {
                FD_ZERO(&fds);
                FD_SET(fd, &fds);

                /* Timeout. */
                tv.tv_sec = 2;
                tv.tv_usec = 0;

                ret = select(fd + 1, &fds, NULL, NULL, &tv);
        } while ((ret == -1 && (errno = EINTR)));
        if (ret == -1) {
                qDebug("select");
                return;
        }

        CLEAR(buf);
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        if(-1 == ioctl(fd, VIDIOC_DQBUF, &buf))
        {
            perror("VIDIOC_DQBUF");
            return;
        }
        if(NULL != pSurface)
        {
           AvSDLYUVDisplay(pSurface, (unsigned char*)videio_buffers[buf.index].start, buf.bytesused) ;
        }
//        fwrite((unsigned char*)videio_buffers[buf.index].start, 1, buf.bytesused, fout);
        if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
        {
            perror("VIDIOC_QBUF");
            return;
        }
        di++;
        qDebug() << "framesize=" << di << ";size = " << buf.bytesused;

   }
    try{
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd, VIDIOC_STREAMOFF, &type);
    for (int i = 0; i < i; ++i)
           v4l2_munmap(videio_buffers[i].start, videio_buffers[i].length);

        v4l2_close(fd);
    }catch(...){}
}
CaptureThread::~CaptureThread()
{
    try{
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd, VIDIOC_STREAMOFF, &type);
    /*for (int i = 0; i < i; ++i)
           v4l2_munmap(videio_buffers[i].start, videio_buffers[i].length);*/

        v4l2_close(fd);
    }catch(...){}
    fd = -1;
}
void CaptureThread::stopCapture()
{
    devam=false;
    try{
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd, VIDIOC_STREAMOFF, &type);
    for (int i = 0; i < i; ++i)
           v4l2_munmap(videio_buffers[i].start, videio_buffers[i].length);

        v4l2_close(fd);
    }catch(...){}
    fd = -1;

}
void CaptureThread::startCapture()
{
    this->start();

}

//void CaptureThread::onStopCapture()
//{
//    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//    xioctl(fd, VIDIOC_STREAMOFF, &type);
//    for (int i = 0; i < i; ++i)
//           v4l2_munmap(videio_buffers[i].start, videio_buffers[i].length);
//    v4l2_close(fd);
//}

